import javax.swing.*;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.beans.PropertyVetoException;
import java.util.Arrays;
import java.util.Random;

public class Game2048 extends JPanel {
    private static final int SIZE = 4;
    private static final int SQUARE_A =100;
    private int[][]grid =new int[SIZE][SIZE];
    private final Random random = new Random();
    private boolean win = false;
    private boolean lose = false;

    Game2048(){
        setFocusable(true);
        //生成两个随机值，填入grid
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                super.keyPressed(e);
                if(!win && !lose){
                    switch (e.getKeyCode()){
                        case KeyEvent.VK_LEFT -> moveLeft();
                        case KeyEvent.VK_RIGHT -> moveRight();
                        case KeyEvent.VK_UP -> moveUp();
                        case KeyEvent.VK_DOWN  -> moveDown();

                    }
                    repaint( );
                    spawnTile();
                    checkGameState();

                }
            }

        });
        spawnTile();
        spawnTile();
    }

    private void moveLeft(){
        for(int row=0;row<SIZE;row++){
            int[] mergedROW = new int[SIZE];
            Arrays.fill(mergedROW,0);
            boolean[] alreadyMerged = new boolean[SIZE];
            Arrays.fill(alreadyMerged,false);
            int colIndex = 0;
            for(int col=0;col<SIZE;col++){
                if(grid[row][col]!=0){
                    if(colIndex == 0){
                        mergedROW[colIndex] = grid[row][col];
                        colIndex++;
                    }else{
                        if(grid[row][col] == mergedROW[colIndex-1]&&!alreadyMerged[colIndex - 1]){
                            mergedROW[colIndex - 1] *= 2;
                            alreadyMerged[colIndex] = true;
                        }else {
                            mergedROW[colIndex] = grid[row][col];
                            colIndex++;
                        }
                    }

                }
            }
            System.arraycopy(mergedROW,0,grid[row],0,SIZE);
        }
    }

    private void moveRight(){
        //转180度
        rotateRight();
        rotateRight();
        moveLeft();
        //转180度
        rotateRight();
        rotateRight();
    }

    private void moveUp(){
        //转270度
        rotateRight();
        rotateRight();
        rotateRight();
        moveLeft();
        //转90度
        rotateRight();
    }

    private void moveDown(){
        //转90度
        rotateRight();
        moveLeft();
        //转270度
        rotateRight();
        rotateRight();
        rotateRight();
    }

    private void rotateRight(){
        int [][] newGrid =new int[SIZE][SIZE];
        for(int row=0;row<SIZE;row++){
            for(int col=0;col<SIZE;col++){
                newGrid[col][SIZE-1-row] = grid[row][col];
            }
        }
        grid = newGrid;
    }

    private void checkGameState(){
        int cnt = 0;
        for(int row=0;row<SIZE;row++){
            for(int col=0;col<SIZE;col++){
                if(grid[row][col] == 2048){
                    win = true;
                    break;
                }else{
                    if(grid[row][col]!=0){
                        cnt++;
                    }
                }
            }
            if(win)
                break;
        }
        if(!win){
            if(cnt<SIZE * SIZE){
                return;
            }
            for (int row = 0;row<SIZE;row++){
                for (int col = 0;col<SIZE;col++){
                    if(row<SIZE-1 && grid[row][col] == grid[row+1][col]){
                        return;
                    }
                    if(col<SIZE-1 && grid[row][col] == grid[row][col+1]){
                        return;
                    }
                }
            }
            lose = true;
        }
    }

    private void spawnTile(){
        int cnt = 0;
        for (int row = 0;row<SIZE;row++){
            for (int col = 0;col<SIZE;col++){
                if(grid[row][col]!=0){
                    cnt++;
                }
            }
        }
        if(cnt == SIZE*SIZE){
            return;
        }
        int x,y;
        do {
             x = random.nextInt(SIZE);
             y = random.nextInt(SIZE);
        }while (grid[x][y]!=0);
        grid[x][y] = random.nextInt(10) < 5 ? 2 : 4;
    }

    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        g.setColor(Color.LIGHT_GRAY);
        g.fillRect(0,0,getWidth(),getHeight());
        for(int row = 0;row < 4;row++){
            for(int col = 0;col < 4;col++){
                //画小正方形
                drawTile(g,grid[row][col],col*SQUARE_A,row*SQUARE_A);
            }
        }
        g.setColor(Color.BLACK);
        if(win){
            g.drawString("You Win!",getWidth()/2,getHeight()/2);
        }
        if(lose){
            g.drawString("Game Over!",getWidth()/2,getHeight()/2);
        }
        //g.drawRect();
        //g.fillRect();
    }

    private void drawTile(Graphics g,int value,int x,int y){
        int m =(int) (Math.log(value)/Math.log(2));
        g.setColor(value == 0 ? Color.GRAY: new Color (255-m*20,240,200));
        g.fillRect(x,y,SQUARE_A,SQUARE_A);
        g.setColor(Color.BLACK);
        g.drawRect(x,y,SQUARE_A,SQUARE_A);

        if(value !=0){
            FontMetrics fm =g.getFontMetrics();
            int textX = x +(SQUARE_A - fm.stringWidth(String.valueOf(value)))/2;
            int textY = y +(SQUARE_A - fm.getHeight())/2 +fm.getAscent();
            g.drawString(String.valueOf(value),textX,textY);
        }

    }
    public static void main(String[] args) {
        JFrame frame = new JFrame("2048 Game");
        Game2048 game2048 = new Game2048();
        frame.setSize(420,460);
        frame.add(game2048);
        frame.setVisible(true);
    }
}